#include "glare.core.Win32Window.h"
#include "glare.core.RenderWindow.h"
#include "glare.core.Driver.h"

namespace Glare {

	Win32Window::Win32Window(const uint& width, const uint& height, ConstructionParams* params)
		: PlatformWindow(width, height)
		, _construction_params(static_cast<Win32WindowConstructionParams*>(params))
	{
		HINSTANCE instance = (HINSTANCE)_construction_params->InstanceHandle;

		if(!instance)
			instance = GetModuleHandle(0);

		WNDCLASSEX wcex;
		wcex.cbSize = sizeof( WNDCLASSEX );
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		wcex.lpfnWndProc = WndProc;
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = instance;
		wcex.hIcon = NULL;
		wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
		wcex.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
		wcex.lpszMenuName = NULL;
		wcex.lpszClassName = _construction_params->Class.c_str();
		wcex.hIconSm = NULL;
		if( !RegisterClassEx( &wcex ) )
			throw Exception(("unable to register window class: " + _construction_params->Class).c_str());

		// Create window
		RECT rc = { 0, 0, GetWidth(), GetHeight() };
		AdjustWindowRectEx(&rc, WS_CAPTION | WS_SYSMENU, false, 0);

		_hwnd = CreateWindow(
			_construction_params->Class.c_str(), 
			_construction_params->Title.c_str(), 
			WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT, 
			CW_USEDEFAULT, 
			GetWidth(), GetHeight(), 
			NULL, 
			NULL, 
			instance,
			NULL);

		if( !_hwnd )
			throw Exception(("unable create window from class: " + _construction_params->Class).c_str());

		ShowWindow(_hwnd, SW_SHOW);
	}

	Win32Window::~Win32Window()
	{
		DestroyWindow(_hwnd);
	}

	const PlatformWindowType Win32Window::GetWindowType() const
	{
		return PWT_Win32;
	}

	const uint Win32Window::GetCanvasWidth(const RenderWindow* render_window) const
	{
		const string& driver_name = render_window->GetDriver()->GetName();

		RECT rc;

		if (driver_name == "GLES2")
			GetClientRect(_hwnd, &rc);
		else
			GetWindowRect(_hwnd, &rc);

		return rc.right - rc.left;
	}

	const uint Win32Window::GetCanvasHeight(const RenderWindow* render_window) const
	{
		const string& driver_name = render_window->GetDriver()->GetName();

		RECT rc;

		if (driver_name == "GLES2")
			GetClientRect(_hwnd, &rc);
		else
			GetWindowRect(_hwnd, &rc);

		return rc.bottom - rc.top;
	}

	const HWND& Win32Window::GetWindowHandle() const
	{
		return _hwnd;
	}

	LRESULT CALLBACK Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
	{
		switch (message)
		{
			/*
			Here we are handling 2 system messages: screen saving and monitor power.
			They are especially relevant on mobile devices.
			*/
#ifndef UNDER_CE
		case WM_SYSCOMMAND:
			{
				switch (wParam)
				{
				case SC_SCREENSAVE:					// Screensaver trying to start ?
				case SC_MONITORPOWER:				// Monitor trying to enter powersave ?
					return 0;							// Prevent this from happening
				}
				break;
			}
#endif
			// Handles the close message when a user clicks the quit icon of the window
		case WM_CLOSE:
			//g_bDemoDone = true;
			PostQuitMessage(0);
			return 1;

		default:
			break;
		}

		// Calls the default window procedure for messages we did not handle
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
}
